package com.icesoft.framework.core.util;


import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.*;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

/**
 * 获取IP的方法
 */
@Slf4j
public class IpUtil {
	private static final String LOCAL_IP = "127.0.0.1";
	//使用腾讯的接口经过ip拿到城市信息
	private static final String KEY = "44LBZ-ERAE3-IXY3Z-YM344-425KF-DUFRT";

	/**
	 * 获取IP地址
	 * <p>
	 * 使用Nginx等反向代理软件， 则不能通过request.getRemoteAddr()获取IP地址
	 * 如果使用了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP地址，X-Forwarded-For中第一个非unknown的有效IP字符串，则为真实IP地址
	 */
	public static String getIpAddr(HttpServletRequest request) {
		if (request == null) {
			return "unknown";
		}
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Forwarded-For");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Real-IP");
		}

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}

		return "0:0:0:0:0:0:0:1".equals(ip) ? LOCAL_IP : ip;
	}

	public static boolean internalIp(String ip) {
		boolean res = false;
		byte[] addr = textToNumericFormatV4(ip);
		if (addr != null && ip != null) {
			res = internalIp(addr) || LOCAL_IP.equals(ip);
		}
		return res;
	}

	private static boolean internalIp(byte[] addr) {
		final byte b0 = addr[0];
		final byte b1 = addr[1];
		// 10.x.x.x/8
		final byte SECTION_1 = 0x0A;
		// 172.16.x.x/12
		final byte SECTION_2 = (byte) 0xAC;
		final byte SECTION_3 = (byte) 0x10;
		final byte SECTION_4 = (byte) 0x1F;
		// 192.168.x.x/16
		final byte SECTION_5 = (byte) 0xC0;
		final byte SECTION_6 = (byte) 0xA8;
		boolean flag = false;
		switch (b0) {
			case SECTION_1:
				flag = true;
				break;
			case SECTION_2:
				if (b1 >= SECTION_3 && b1 <= SECTION_4) {
					flag = true;
				}
				break;
			case SECTION_5:
				if (b1 == SECTION_6) {
					flag = true;
				}
				break;
			default:
				break;
		}
		return flag;
	}

	/**
	 * 将IPv4地址转换成字节
	 * IPv4地址
	 *
	 * @param text
	 * @return byte 字节
	 */
	public static byte[] textToNumericFormatV4(String text) {
		if (text.length() == 0) {
			return null;
		}

		byte[] bytes = new byte[4];
		String[] elements = text.split("\\.", -1);
		try {
			long l;
			int i;
			switch (elements.length) {
				case 1:
					l = Long.parseLong(elements[0]);
					if ((l < 0L) || (l > 4294967295L))
						return null;
					bytes[0] = (byte) (int) (l >> 24 & 0xFF);
					bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
					bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
					bytes[3] = (byte) (int) (l & 0xFF);
					break;
				case 2:
					l = Integer.parseInt(elements[0]);
					if ((l < 0L) || (l > 255L))
						return null;
					bytes[0] = (byte) (int) (l & 0xFF);
					l = Integer.parseInt(elements[1]);
					if ((l < 0L) || (l > 16777215L))
						return null;
					bytes[1] = (byte) (int) (l >> 16 & 0xFF);
					bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
					bytes[3] = (byte) (int) (l & 0xFF);
					break;
				case 3:
					for (i = 0; i < 2; ++i) {
						l = Integer.parseInt(elements[i]);
						if ((l < 0L) || (l > 255L))
							return null;
						bytes[i] = (byte) (int) (l & 0xFF);
					}
					l = Integer.parseInt(elements[2]);
					if ((l < 0L) || (l > 65535L))
						return null;
					bytes[2] = (byte) (int) (l >> 8 & 0xFF);
					bytes[3] = (byte) (int) (l & 0xFF);
					break;
				case 4:
					for (i = 0; i < 4; ++i) {
						l = Integer.parseInt(elements[i]);
						if ((l < 0L) || (l > 255L))
							return null;
						bytes[i] = (byte) (int) (l & 0xFF);
					}
					break;
				default:
					return null;
			}
		} catch (Exception e) {
			log.error("数字格式化异常", e);
			return null;
		}
		return bytes;
	}

	public static String getLocalIP() {
		String ip = "";
		if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
			InetAddress addr;
			try {
				addr = InetAddress.getLocalHost();
				ip = addr.getHostAddress();
			} catch (Exception e) {
				log.error("获取失败", e);
			}
			return ip;
		} else {
			try {
				Enumeration<?> e1 = NetworkInterface
						.getNetworkInterfaces();
				while (e1.hasMoreElements()) {
					NetworkInterface ni = (NetworkInterface) e1.nextElement();
					if (!ni.getName().equals("eth0")) {
						continue;
					} else {
						Enumeration<?> e2 = ni.getInetAddresses();
						while (e2.hasMoreElements()) {
							InetAddress ia = (InetAddress) e2.nextElement();
							if (ia instanceof Inet6Address)
								continue;
							ip = ia.getHostAddress();
							return ip;
						}
						break;
					}
				}
			} catch (SocketException e) {
				log.error("获取失败", e);
			}
		}
		return "";
	}

	public static String getCityInfo(HttpServletRequest request) {
		String s = sendGet(getIpAddr(request), KEY);
		Map map = JSONObject.parseObject(s, Map.class);
		String message = (String) map.get("message");
		if ("query ok".equals(message)) {
			Map result = (Map) map.get("result");
			Map addressInfo = (Map) result.get("ad_info");
			String nation = (String) addressInfo.get("nation");
			String province = (String) addressInfo.get("province");
			String city = (String) addressInfo.get("city");
			return nation + "-" + province + "-" + city;
		} else {
			return null;
		}
	}

	//根据在腾讯位置服务上申请的key进行请求操做
	public static String sendGet(String ip, String key) {
		BufferedReader in = null;
		try {
			String result = "";
			String urlNameString = "https://apis.map.qq.com/ws/location/v1/ip?ip=" + ip + "&key=" + key;
			URL realUrl = new URL(urlNameString);
			// 打开和URL之间的链接
			URLConnection connection = realUrl.openConnection();
			// 设置通用的请求属性
			connection.setRequestProperty("accept", "*/*");
			connection.setRequestProperty("connection", "Keep-Alive");
			connection.setRequestProperty("user-agent",
					"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			// 创建实际的链接
			connection.connect();
			// 获取全部响应头字段
			Map<String, List<String>> map = connection.getHeaderFields();
			// 遍历全部的响应头字段
//            for (Map.Entry entry : map.entrySet()) {
//                System.out.println(key + "--->" + entry);
//            }
			// 定义 BufferedReader输入流来读取URL的响应
			in = new BufferedReader(new InputStreamReader(
					connection.getInputStream()));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
			return result;
		} catch (Exception e) {
			System.out.println("发送GET请求出现异常！" + e);
			e.printStackTrace();
			return null;
		}
		// 使用finally块来关闭输入流
		finally {
			try {
				if (in != null) {
					in.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}

	}

}
